package com.stp.yupao.utils;

import io.swagger.models.auth.In;

import java.util.*;

/**
 * 基于标签相似度的用户推荐
 */
public class UserToUserTagRecommender {
    // 用户-标签矩阵: key=用户ID, value=标签及其权重
    private Map<Long, Map<String, Double>> userTagMatrix;

    public UserToUserTagRecommender() {
        this.userTagMatrix = new HashMap<>();
    }

    // 添加用户标签数据
    public void addUserTag(Long userId, String tag, double weight) {
        userTagMatrix.computeIfAbsent(userId, k -> new HashMap<>()).put(tag, weight);
    }

    // 计算余弦相似度
    private double cosineSimilarity(Map<String, Double> user1Tags, Map<String, Double> user2Tags) {
        double dotProduct = 0.0;
        double norm1 = 0.0;
        double norm2 = 0.0;

        // 计算点积和向量模
        for (String tag : user1Tags.keySet()) {
            if (user2Tags.containsKey(tag)) {
                dotProduct += user1Tags.get(tag) * user2Tags.get(tag);
            }
            norm1 += Math.pow(user1Tags.get(tag), 2);
        }

        for (Double value : user2Tags.values()) {
            norm2 += Math.pow(value, 2);
        }

        if (norm1 == 0 || norm2 == 0) {
            return 0.0;
        }
        return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
    }

    // 为用户推荐其他用户
    public List<Long> recommendUsers(Long targetUserId, Integer topN, Set<Long> excludedUsers) {
        if (!userTagMatrix.containsKey(targetUserId)) {
            return Collections.emptyList();
        }

        Map<String, Double> targetUserTags = userTagMatrix.get(targetUserId);
        PriorityQueue<UserScore> pq = new PriorityQueue<>(topN, Comparator.comparingDouble(UserScore::getScore));

        for (Long userId : userTagMatrix.keySet()) {
            // 跳过目标用户自己和排除列表中的用户
            if (userId == targetUserId || excludedUsers.contains(userId)) {
                continue;
            }

            Map<String, Double> candidateTags = userTagMatrix.get(userId);
            double similarity = cosineSimilarity(targetUserTags, candidateTags);

            if (pq.size() < topN) {
                pq.offer(new UserScore(userId, similarity));
            } else if (similarity > pq.peek().getScore()) {
                pq.poll();
                pq.offer(new UserScore(userId, similarity));
            }
        }

        List<Long> recommendations = new ArrayList<>(topN);
        while (!pq.isEmpty()) {
            recommendations.add(0, pq.poll().getUserId());
        }

        return recommendations;
    }

    public static void main(String[] args) {
        // 创建推荐器
        UserToUserTagRecommender recommender = new UserToUserTagRecommender();

        // 添加用户标签数据
        recommender.addUserTag(1L, "编程", 1.0);
        recommender.addUserTag(1L, "算法", 0.8);
        recommender.addUserTag(1L, "Java", 0.9);

        recommender.addUserTag(2L, "编程", 0.8);
        recommender.addUserTag(2L, "Python", 0.9);
        recommender.addUserTag(2L, "机器学习", 0.7);

        recommender.addUserTag(3L, "Java", 1.0);
        recommender.addUserTag(3L, "Spring", 0.9);
        recommender.addUserTag(3L, "后端", 0.8);

        recommender.addUserTag(4L, "绘画", 1.0);
        recommender.addUserTag(4L, "设计", 0.8);
        recommender.addUserTag(4L, "艺术", 0.7);

        // 获取推荐
        Set<Long> excluded = new HashSet<>(Arrays.asList(1L)); // 排除自己
        List<Long> recommendations = recommender.recommendUsers(1L, 2, excluded);
        System.out.println("推荐用户ID: " + recommendations); // 应该推荐用户3和用户2
    }
}
